package com.forum.framework.security.config;

import com.forum.framework.security.core.filter.TokenAuthenticationFilter;
import com.forum.framework.security.core.handler.AuthenticationEntryPointImpl;
import com.forum.framework.web.core.handler.GlobalExceptionHandler;
import com.forum.module.system.api.oauth2.OAuth2TokenApi;
import jakarta.annotation.Resource;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.CorsFilter;

/**
 * 自定义的 Spring Security 配置适配器实现
 *
 * @author zihan.ouyang
 */
@AutoConfiguration
@AutoConfigureOrder(-1) // 目的：先于 Spring Security 自动配置，避免一键改包后，org.* 基础包无法生效
@EnableMethodSecurity(securedEnabled = true)
public class ForumWebSecurityConfigurationAdapter {
    @Resource
    private OAuth2TokenApi oAuth2TokenApi;
    @Resource
    private GlobalExceptionHandler globalExceptionHandler;

    @Bean
    public AuthenticationEntryPointImpl authenticationEntryPoint() {
        return new AuthenticationEntryPointImpl();
    }

    @Bean
    public TokenAuthenticationFilter tokenAuthenticationFilter() {
        return new TokenAuthenticationFilter(securityProperties(), oAuth2TokenApi, globalExceptionHandler);
    }

    @Bean
    SecurityProperties securityProperties() {
        return new SecurityProperties();
    }


    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity security) throws Exception {
        security
                .csrf(csrf -> csrf.disable())
                .headers((headersCustomizer) -> {
                    headersCustomizer.cacheControl(cache -> cache.disable()).frameOptions(options -> options.sameOrigin());
                })
                .exceptionHandling(exception -> exception.authenticationEntryPoint(authenticationEntryPoint()))
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers("/admin-api/system/auth/*",
                                "/system/captcha/*",
                                "/system/oauth2/token/*",
                                "/system/user/*",
                                "/druid/*",
                                "/druid",
                                "/admin-api/system/file/download",
                                "/admin-api/admin/user/forgot-password",
                                "/admin-api/system/mail/code").permitAll()
                        .requestMatchers("/v3/api-docs", "/swagger-ui.html", "/webjars/**", "/swagger-resources/**", "/doc.html", "/css/**", "/js/**", "/swagger-ui/**", "/v3/api-docs/swagger-config", "/api-doc/").permitAll()
                        .anyRequest().authenticated()
                )
                .addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        return security.build();
    }
}
